#include "rating.hh"
#include "rule.hh"
#include "workflows.hh"
#include <iostream>

#include <fstream>
#include <vector>
#include <unordered_map>
#include <algorithm>

auto getWorkflows(std::ifstream& infile) -> std::unordered_map<std::string, Workflow> 
{
    std::unordered_map<std::string, Workflow> workflows {};
    std::string line {};
    while (std::getline(infile, line))
    {
        if (line.empty()) break;
        Workflow workflow {line};
        workflows.emplace(workflow.name(), std::move(workflow));
    }
    return workflows;
}

auto getRatings(std::ifstream& infile) -> std::vector<Rating>
{
    std::vector<Rating> ratings {};
    std::string line {};
    while (std::getline(infile, line))
    {
        ratings.emplace_back(line);
    }
    return ratings;
}

bool accept(const std::unordered_map<std::string, Workflow>& workflows, Rating* rating)
{
    // Begin with 'in'
    const Workflow* workflow {nullptr};
    auto res {workflows.find("in")};
    workflow = &(res->second);

    while (true)
    {
        auto[result, next] {workflow->result(rating)};
        switch (result)
        {
            case WorkflowResult::Accept: 
            {
                return true;
            }
            case WorkflowResult::Reject:
            {
                return false;
            }
            case WorkflowResult::Jump:
            {
                if (next == "A") 
                {
                    return true;
                }
                else if (next == "R") 
                {
                    return false;
                }
                workflow = &(workflows.find(next)->second);
            }
        }
    }
} 

int main()
{
    std::ifstream infile {"./src/day19/input.txt"};
    auto workflows {getWorkflows(infile)};
    // std::for_each(workflows.cbegin(), workflows.cend(), [](const Workflow& w) {
    //     w.print();
    // });

    auto ratings {getRatings(infile)};
    // std::for_each(ratings.cbegin(), ratings.cend(), [](const Rating& r) {
    //     r.print();
    // });

    int sum = 0;
    std::for_each(ratings.begin(), ratings.end(), [&workflows, &sum](Rating& rating){
        if (accept(workflows, &rating))
        {
            int partSum = rating.attr('x') + rating.attr('m') + rating.attr('a') + rating.attr('s');
            sum += partSum;
        }
    });
    std::cout << sum << std::endl;

    return 0;
}